package pkg

import (
	"bytes"
	"fmt"
	"github.com/kbinani/screenshot"
	"github.com/otiai10/gosseract/v2"
	"image"
	"image/color"
	"image/png"
	"io"
	"io/ioutil"
	"k8s.io/klog"
	"os"
	"os/exec"
	"sort"
	"strconv"
	"strings"
	"unicode"
	"unicode/utf8"
	"regexp"
)

func copy(src, dst string) (int64, error) {
	sourceFileStat, err := os.Stat(src)
	if err != nil {
		return 0, err
	}

	if !sourceFileStat.Mode().IsRegular() {
		return 0, fmt.Errorf("%s is not a regular file", src)
	}

	source, err := os.Open(src)
	if err != nil {
		return 0, err
	}
	defer source.Close()

	destination, err := os.Create(dst)
	if err != nil {
		return 0, err
	}
	defer destination.Close()
	nBytes, err := io.Copy(destination, source)
	return nBytes, err
}


func getBbox()(int,int,int,int,error){
	cmd:=exec.Command("xdotool","getwindowfocus", "getwindowgeometry")
//	if err:=cmd.Start();err!=nil{
//		klog.Errorf("get bbox error:%v",err)
//		return 0, 0, 0, 0, err
//	}
	msg,err:=cmd.Output()
	if err!=nil{
		klog.Errorf("get bbox error:%v",msg)
		return 0, 0, 0, 0, err
	}
	xy:=regexp.MustCompile(`Position: (\d+)?,(\d+)? \(.*`);
	wh:=regexp.MustCompile(`Geometry: (\d+)?x(\d+)?`)
	xyMatch:=xy.FindStringSubmatch(string(msg))
	whMatch:=wh.FindStringSubmatch(string(msg))
	x,err:=strconv.Atoi(xyMatch[1])
        klog.Errorf("%s",msg)
        klog.Errorf("%v   %v",xyMatch,whMatch)
	if err!=nil{
		klog.Errorf("get bbox error:%v",err)
		return 0, 0, 0, 0, err
	}
	y,err:=strconv.Atoi(xyMatch[2])
	if err!=nil{
		klog.Errorf("get bbox error:%v",err)
		return 0, 0, 0, 0, err
	}
	w,err:=strconv.Atoi(whMatch[1])
	if err!=nil{
		klog.Errorf("get bbox error:%v",err)
		return 0, 0, 0, 0, err
	}
	h,err:=strconv.Atoi(whMatch[2])
	if err!=nil{
		klog.Errorf("get bbox error:%v",err)
		return 0, 0, 0, 0, err
	}
	return x,y,w,h,nil
}

func sortButtons(buttons []Button) []Button{
	lessFunc:=func(i,j int)bool{
		if buttons[i].ButtonType>buttons[j].ButtonType{
			return false
		}
		return buttons[i].Name<buttons[j].Name
	}

	sort.Slice(buttons,lessFunc)
	return buttons
}


func pathExists(path string)(bool,error){
	_,err:=os.Stat(path)
	if err!=nil{
		if os.IsNotExist(err){
			return false,nil
		}
		return false,err
	}
	return true,nil
}

func ocrImage(path string,isWine bool)(string,error){
       
	newPath:=path
	path="./tmp.png"
	processImage(newPath,path)
	defer os.Remove(path)
	client := gosseract.NewClient()
	defer client.Close()
	err:=client.SetImage(path)
	if err!=nil{
		klog.Errorf("ocr client set image error:%v",err)
		return "", err
	}
	text, err := client.Text()
	if err!=nil{
		klog.Errorf("ocr client get image text error:%v",err)
		return "", err
	}
	return text,nil
}

// levenshtein
func computeDistance(a, b string) int {

	if len(a) == 0 {
		return utf8.RuneCountInString(b)
	}

	if len(b) == 0 {
		return utf8.RuneCountInString(a)
	}

	if a == b {
		return 0
	}

	// We need to convert to []rune if the strings are non-ASCII.
	// This could be avoided by using utf8.RuneCountInString
	// and then doing some juggling with rune indices,
	// but leads to far more bounds checks. It is a reasonable trade-off.
	s1 := []rune(a)
	s2 := []rune(b)

	// swap to save some memory O(min(a,b)) instead of O(a)
	if len(s1) > len(s2) {
		s1, s2 = s2, s1
	}
	lenS1 := len(s1)
	lenS2 := len(s2)

	// init the row
	x := make([]uint16, lenS1+1)
	// we start from 1 because index 0 is already 0.
	for i := 1; i < len(x); i++ {
		x[i] = uint16(i)
	}

	// make a dummy bounds check to prevent the 2 bounds check down below.
	// The one inside the loop is particularly costly.
	_ = x[lenS1]
	// fill in the rest
	for i := 1; i <= lenS2; i++ {
		prev := uint16(i)
		for j := 1; j <= lenS1; j++ {
			current := x[j-1] // match
			if s2[i-1] != s1[j-1] {
				current = min(min(x[j-1]+1, prev+1), x[j]+1)
			}
			x[j-1] = prev
			prev = current
		}
		x[lenS1] = prev
	}
	return int(x[lenS1])
}

func min(a, b uint16) uint16 {
	if a < b {
		return a
	}
	return b
}


func isSimilar(name1,name2 string)bool{
	name1,name2=filterChar(name1),filterChar(name2)
        if len(name1)<=3{
               name1=""
        }
        
        if len(name2)<=3{
               name2=""
        }
	distance:=computeDistance(name1,name2)
	
	minLen:=len(name1)
	if len(name2)<minLen{
		minLen=len(name2)
	}
	klog.Infof("wine button %s and windows button %s distance is %d similar num is %f",name1,name2,distance,float64(distance)/float64(minLen))
	return float64(distance)/(float64(minLen)+0.001)<=2
}

func filterChar(str string)string{
	str=strings.ToLower(str)
	newStr:=""
	for i:=range str{
		if unicode.IsDigit(rune(str[i])) || unicode.IsLetter(rune(str[i])){
			newStr=fmt.Sprintf("%s%s",newStr,string(str[i]))
		}
	}
	return newStr
}



func captureImage(imageButton imageButton,path string)error{
	// replace imageButton
	x,y,w,h,err:=getBbox()
	if err!=nil{
		klog.Errorf("capture image error:%v",err)
		return err
	}
        // y+20 : not caputure title
	imageButton.x,imageButton.y,imageButton.width,imageButton.height=x,y,w,h
        klog.Errorf("%d\t%d\t%d\t%d",x,y,w,h)
	num:=screenshot.NumActiveDisplays()
	bounds := screenshot.GetDisplayBounds(num-1)
	// 截取该屏幕截图
	img, err := screenshot.Capture(bounds.Min.X+imageButton.x,bounds.Min.Y+imageButton.y,bounds.Min.X+imageButton.width,bounds.Min.Y+imageButton.height)
	if err!=nil{
		klog.Errorf("capture images error:%v",err)
		return err
	}

	file, err := os.Create(path)
	if err!=nil{
		klog.Errorf("create file %s error:%v",path,err)
		return err
	}
	defer file.Close()
	png.Encode(file, img)

	return nil
}


func mkdirIfNotFound(path string)error{

	found,err:=pathExists(path)
	if err!=nil{
		klog.Errorf("judge path exists error:%v\n",err)
		return err
	}

	if !found{
		err:=os.MkdirAll(path,os.ModePerm)
		if err!=nil{
			klog.Errorf("mkdir %s error:%v\n",path,err)
			return err
		}else{
			klog.Infof("mkdir %s success\n",path)
		}
	}else{
		klog.Infof("Dir %s exists\n",path)
	}
	return nil
}

func killAPP(name string){
	command:=fmt.Sprintf("ps -ef | grep %s | awk '{print \"kill -9 \"$2}' | bash",name)
	cmd := exec.Command("/bin/bash", "-c", command)
	err:=cmd.Start()
	if err!=nil{
		fmt.Printf("%v",err)
	}
}



func processImage(path,target string){
	ff, _ := ioutil.ReadFile(path) //读取文件
	bbb := bytes.NewBuffer(ff)
	m, _, _ := image.Decode(bbb)
	bounds := m.Bounds()
	dx := bounds.Dx()
	dy := bounds.Dy()
	newRgba := image.NewRGBA(bounds) //new 一个新的图片
	for i := 0; i < dx; i++ {
		for j := 0; j < dy; j++ {
			colorRgb := m.At(i, j)

			r, g, b, a := colorRgb.RGBA()
			r_uint8 := uint8(r >> 8)	//转换为 255 值
			g_uint8 := uint8(g >> 8)
			b_uint8 := uint8(b >> 8)
			a_uint8 := uint8(a >> 8)
			// 背景设置为白色
			if r_uint8> 20 && g_uint8>20 && b_uint8>20{
				r_uint8=255
				g_uint8=255
				b_uint8=255
				a_uint8=255
			}
			newRgba.SetRGBA(i, j, color.RGBA{r_uint8, g_uint8, b_uint8, a_uint8}) //设置像素点
		}
	}
	f, _ := os.Create(target)
	defer f.Close()
	png.Encode(f,newRgba)
}
